package cn.stylefeng.guns.modular.robot.cmd.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.stylefeng.guns.modular.robot.cmd.abs.AbstractCmd;
import cn.stylefeng.guns.modular.robot.entity.Group;
import cn.stylefeng.guns.modular.robot.entity.LowerMessage;
import cn.stylefeng.guns.modular.robot.entity.Order;
import cn.stylefeng.guns.modular.robot.entity.OrderBatch;
import cn.stylefeng.guns.modular.robot.entity.enums.GroupMode;
import cn.stylefeng.guns.modular.robot.entity.vo.req.CmdPlusReq;
import cn.stylefeng.guns.modular.robot.entity.vo.resp.BatchInfo;
import cn.stylefeng.guns.modular.robot.service.GroupService;
import cn.stylefeng.guns.modular.robot.service.LowerMessageService;
import cn.stylefeng.guns.modular.robot.service.OrderBatchService;
import cn.stylefeng.guns.modular.robot.service.OrderService;
import cn.stylefeng.guns.modular.robot.utils.RobotUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

@Slf4j
@Service
@Transactional
public class CmdPlus extends AbstractCmd {

    @Resource
    private OrderService orderService;
    @Resource
    private GroupService groupService;
    @Resource
    private OrderBatchService orderBatchService;
    @Resource
    private LowerMessageService lowerMessageService;
    @Resource
    private CmdZero cmdZero;
    @Value("${local.url}")
    private String localUrl;

    @Override
    public void exec(Update update, TelegramLongPollingBot bot) {
        String text = update.getMessage().getText().trim();
        if ("+0".equals(text)) {
            cmdZero.exec(update, bot);
            return;
        }
        Long chatId = update.getMessage().getChatId();
        CmdPlusReq cmdPlusReq = analysisCmd(text);
        Group group = groupService.getGroupByTgGroupId(chatId);
        if (!Boolean.TRUE.equals(group.getBatchStatus())) {
            RobotUtils.sendText(chatId, "记账未开启！", bot);
            return;
        }
        List<OrderBatch> orderBatches = orderBatchService.lambdaQuery()
                .eq(OrderBatch::getBatchId, group.getBatchId())
                .list();
        OrderBatch orderBatch = orderBatches.get(0);
        if (GroupMode.币.equals(orderBatch.getGroupMode()) && (GroupMode.USDT.equals(cmdPlusReq.getGroupMode()) || text.contains("/"))) {
            StringBuilder sb = new StringBuilder();
            sb.append("当前是币本位模式\n");
            sb.append("正确格式为：+(数字)");
            RobotUtils.sendText(chatId, sb.toString(), bot);
            return;
        }
        if (BigDecimal.ZERO.compareTo(cmdPlusReq.getExchangeRate()) != 0) {
            group.setExchangeRate(cmdPlusReq.getExchangeRate());
            groupService.updateById(group);
        }
        LowerMessage optionLowerMessage = getOptionLowerMessage(update);
        Group lowerGroup = null;
        if (!Objects.isNull(optionLowerMessage)) {
            lowerGroup = groupService.getGroupByTgGroupId(optionLowerMessage.getGroupId());
        }
        if (GroupMode.USDT.equals(cmdPlusReq.getGroupMode()) && GroupMode.USDT.equals(orderBatch.getGroupMode())) {
            cmdPlusReq.setAmount(cmdPlusReq.getAmount().multiply(group.getExchangeRate()));
        }
        StringBuilder upperSb = new StringBuilder();
        Order oder = createOder(update, group, cmdPlusReq, null, null, upperSb, bot);
        if (text.startsWith("下发")) {
            String url = localUrl + "order/indexBatch?batchId=" + group.getBatchId();
            RobotUtils.sendTextButton(group.getTgGroupId(), upperSb.toString(), "完整账单", url, null, bot);
            return;
        }
        if (!Objects.isNull(lowerGroup) && !Objects.isNull(oder)) {
            StringBuilder lowerSb = new StringBuilder();
            createOder(update, lowerGroup, cmdPlusReq, oder.getId(), optionLowerMessage, lowerSb, bot);

            try {
                String url = localUrl + "order/indexBatch?batchId=" + lowerGroup.getBatchId();
                RobotUtils.sendTextButton(lowerGroup.getTgGroupId(), lowerSb.toString(), "完整账单", url, optionLowerMessage.getLowerMessageId(), bot);

                url = localUrl + "order/indexBatch?batchId=" + group.getBatchId();
                RobotUtils.sendTextButton(group.getTgGroupId(), upperSb.toString(), "完整账单", url, null, bot);
            }catch (Exception e){
                RobotUtils.sendText(group.getTgGroupId(), "加分失败！可能原因为下游群已删除加分图片或者网络出现波动！", bot);
                throw e;
            }
        }else {
            String url = localUrl + "order/indexBatch?batchId=" + group.getBatchId();
            RobotUtils.sendTextButton(group.getTgGroupId(), upperSb.toString(), "完整账单", url, null, bot);
        }
    }

    private CmdPlusReq analysisCmd(String text) {
        CmdPlusReq cmdPlusReq = null;
        String orderType = text.startsWith("下发") ? "下发" : "入款";
        if (text.startsWith("+")) {
            cmdPlusReq = analysisCmd(text, 1);
        } else {
            cmdPlusReq = analysisCmd(text, 2);
        }
        cmdPlusReq.setOrderType(orderType);
        return cmdPlusReq;
    }

    private CmdPlusReq analysisCmd(String text, int index) {
        CmdPlusReq cmdPlusReq = new CmdPlusReq();
        cmdPlusReq.setExchangeRate(BigDecimal.ZERO);
        if (text.contains(" ")) {
            String orderMemo = text.substring(text.indexOf(" ") + 1);
            String start = text.substring(index, text.indexOf(" "));
            if (start.toUpperCase(Locale.ROOT).endsWith("U")) {
                start = start.replace("U", "").replace("u", "");
                cmdPlusReq.setGroupMode(GroupMode.USDT);
            } else {
                cmdPlusReq.setGroupMode(GroupMode.币);
            }
            cmdPlusReq.setOrderMemo(orderMemo);
            if (start.contains("/")) {
                String[] split = start.split("/");
                if (split[0].toUpperCase(Locale.ROOT).endsWith("U")) {
                    split[0] = split[0].replace("U", "").replace("u", "");
                    cmdPlusReq.setGroupMode(GroupMode.USDT);
                }
                BigDecimal amount = new BigDecimal(split[0]);
                BigDecimal exchangeRate = new BigDecimal(split[1]);
                cmdPlusReq.setExchangeRate(exchangeRate);
                cmdPlusReq.setAmount(amount);
            } else {
                BigDecimal amount = new BigDecimal(start);
                cmdPlusReq.setAmount(amount);
            }
        } else {
            String start = text.substring(index);
            if (start.toUpperCase(Locale.ROOT).endsWith("U")) {
                start = start.replace("U", "").replace("u", "");
                cmdPlusReq.setGroupMode(GroupMode.USDT);
            } else {
                cmdPlusReq.setGroupMode(GroupMode.币);
            }
            if (start.contains("/")) {
                String[] split = start.split("/");
                if (split[0].toUpperCase(Locale.ROOT).endsWith("U")) {
                    split[0] = split[0].replace("U", "").replace("u", "");
                    cmdPlusReq.setGroupMode(GroupMode.USDT);
                }
                BigDecimal amount = new BigDecimal(split[0]);
                BigDecimal exchangeRate = new BigDecimal(split[1]);
                cmdPlusReq.setAmount(amount);
                cmdPlusReq.setExchangeRate(exchangeRate);
            } else {
                BigDecimal amount = new BigDecimal(start);
                cmdPlusReq.setAmount(amount);
            }
        }
        if (StringUtils.isBlank(cmdPlusReq.getOrderMemo())) {
            cmdPlusReq.setOrderMemo("");
        }
        return cmdPlusReq;
    }

    public Order createOder(Update update, Group group, CmdPlusReq cmdPlusReq, Long orderId, LowerMessage optionLowerMessage, StringBuilder sb, TelegramLongPollingBot bot) {
//        BatchInfo batchInfo = getBatchInfo(group.getBatchId());
//        if (!verifyBalance(amount, batchInfo)) {
//            RobotUtils.sendText(chatId, "下发失败，批次余额不足", bot);
//            return null;
//        }
        List<OrderBatch> orderBatches = orderBatchService.lambdaQuery()
                .eq(OrderBatch::getBatchId, group.getBatchId())
                .list();
        OrderBatch orderBatch = orderBatches.get(0);
        //创建订单
        Order order = new Order();
        Long customId = update.getMessage().getFrom().getId();
        String customName = update.getMessage().getFrom().getUserName();
        if (!Objects.isNull(optionLowerMessage)) {
            order.setLowerGroupId(optionLowerMessage.getGroupId());
            order.setLowerGroupName(optionLowerMessage.getGroupName());
            order.setLowerCustomId(optionLowerMessage.getCustomId());
            order.setLowerCustomName(optionLowerMessage.getCustomName());
            customId = optionLowerMessage.getCustomId();
            customName = optionLowerMessage.getCustomName();
        }
        order.setBatchId(group.getBatchId());
        order.setOrgId(orderId);
        order.setAmount(cmdPlusReq.getAmount());
        order.setCustomId(customId);
        order.setCustomName(customName);
        order.setGroupId(group.getTgGroupId());
        order.setGroupName(group.getName());
        order.setType(cmdPlusReq.getOrderType());
        order.setRate(group.getRate());
        order.setExchangeRate(group.getExchangeRate());
        order.setExtract(group.getExtract());
        if (GroupMode.币.equals(orderBatch.getGroupMode())) {
            order.setExchangeRate(orderBatch.getExchangeRate());
        }
        order.setUnit(group.getUnit());
        order.setGroupMode(orderBatch.getGroupMode());
        order.setCreateBy(customName);
        order.setCreateTime(new Date());
        order.setMemo(cmdPlusReq.getOrderMemo());
        orderService.save(order);
        BatchInfo batchInfo = getBatchInfo(orderBatch);
        //发送机器人信息
        sendBiResultMsg(batchInfo, update.getMessage().getText(), optionLowerMessage == null ? null : optionLowerMessage.getLowerMessageId(), group, sb, bot);
        sendUResultMsg(batchInfo, update.getMessage().getText(), optionLowerMessage == null ? null : optionLowerMessage.getLowerMessageId(), group, sb, bot);
        return order;
    }

    private void sendUResultMsg(BatchInfo batchInfo, String text, Integer replyToMessageId, Group group, StringBuilder sb, TelegramLongPollingBot bot) {
        if (GroupMode.币.equals(batchInfo.getGroupMode())) {
            return;
        }
        String start = "";
        if (replyToMessageId != null) {
            start = text;
        }
        Long chatId = group.getTgGroupId();
        sb.append(start).append("\n\n");
        sb.append("<b>").append("入款").append(": (").append(batchInfo.getAllInOrders().size()).append("笔)</b>\n");
        for (Order od : batchInfo.getInOrders()) {
            String clearText = Boolean.TRUE.equals(od.getIsDelete()) ? "（清理不入账）" : "";
            String userName = " ";
            if (Boolean.TRUE.equals(batchInfo.getShowOderUser())) {
                userName = " " + od.getMemo() + " ";
            }
            if (!Objects.isNull(od.getExtract()) && BigDecimal.ZERO.compareTo(od.getExtract()) != 0) {
                sb.append(od.getId()).append(userName).append(DateUtil.format(od.getCreateTime(), "HH:mm:ss "))
                        .append("<b>").append("(").append(String.format("%.0f", od.getAmount())).append("-").append(String.format("%.0f", od.getExtract())).append(") / ").append(String.format("%.0f", od.getExchangeRate())).append(" = ")
                        .append(String.format("%.0f", od.getAmount().subtract(od.getExtract()).divide(od.getExchangeRate(), 4, RoundingMode.HALF_UP))).append("U").append(clearText).append("</b>\n");
            } else {
                sb.append(od.getId()).append(userName).append(DateUtil.format(od.getCreateTime(), "HH:mm:ss "))
                        .append("<b>").append(String.format("%.0f", od.getAmount())).append(" / ").append(String.format("%.0f", od.getExchangeRate())).append(" = ")
                        .append(String.format("%.0f", od.getAmount().divide(od.getExchangeRate(), 4, RoundingMode.HALF_UP))).append("U").append(clearText).append("</b>\n");
            }
        }
        sb.append("\n");
        sb.append("<b>").append("下发").append(": (").append(batchInfo.getAllOutOrders().size()).append("笔)</b>\n");
        for (Order od : batchInfo.getOutOrders()) {
            String clearText = Boolean.TRUE.equals(od.getIsDelete()) ? "（清理不入账）" : "";
            String userName = " ";
            if (Boolean.TRUE.equals(batchInfo.getShowOderUser())) {
                userName = " " + od.getMemo() + " ";
            }
            sb.append(od.getId()).append(userName).append(DateUtil.format(od.getCreateTime(), "HH:mm:ss "))
                    .append("<b>").append(String.format("%.0f", od.getAmount().divide(od.getExchangeRate(), 4, RoundingMode.HALF_UP)))
                    .append("U(").append(String.format("%.0f", od.getAmount())).append(")").append(clearText).append("</b>\n");
        }
        sb.append("\n");
        sb.append("<b>总入款: </b>").append(String.format("%.0f", batchInfo.getSumInAmount())).append("\n");
        sb.append("<b>总入U数: </b>").append(String.format("%.0f", batchInfo.getSumInU())).append("\n");
        sb.append("\n");
        sb.append("<b>费率: </b>").append(String.format("%.2f", group.getRate().multiply(BigDecimal.valueOf(100)))).append("%\n");
        sb.append("<b>USD汇率: </b>").append(String.format("%.2f", group.getExchangeRate())).append("\n");
        sb.append("<b>单笔: </b>").append(String.format("%.0f", group.getExtract())).append("\n");
        sb.append("\n");
        sb.append("<b>应下发: </b>").append(String.format("%.0f", batchInfo.getNeedGive())).append(" USDT\n");
        sb.append("<b>总下发: </b>").append(String.format("%.0f", batchInfo.getSumOutAmount())).append(" USDT\n");
        sb.append("<b>剩余: </b>").append(String.format("%.0f", batchInfo.getNeedGive().subtract(batchInfo.getSumOutAmount()))).append(" USDT\n");
        Date batchStartTime = group.getBatchStartTime();
        long time = System.currentTimeMillis() - batchStartTime.getTime();
        sb.append("\n");
        sb.append("已工作").append(time / 1000 / 60).append("分钟");
    }

    private void sendBiResultMsg(BatchInfo batchInfo, String text, Integer replyToMessageId, Group group, StringBuilder sb, TelegramLongPollingBot bot) {
        if (GroupMode.USDT.equals(batchInfo.getGroupMode())) {
            return;
        }
        String start = "";
        if (replyToMessageId != null) {
            start = text;
        }
        Long chatId = group.getTgGroupId();
        sb.append(start).append("\n\n");
        getBiResultString(sb, "入款", batchInfo.getInOrders(), batchInfo.getAllInOrders(), batchInfo);
        sb.append("\n");
        getBiResultString(sb, "下发", batchInfo.getOutOrders(), batchInfo.getAllOutOrders(), batchInfo);
        sb.append("\n");
        sb.append("<b>总入款: </b>").append(String.format("%.0f", batchInfo.getSumInAmount())).append("\n");
        sb.append("<b>费率: </b>").append(String.format("%.2f", group.getRate().multiply(BigDecimal.valueOf(100)))).append("%\n");
        sb.append("<b>单笔: </b>").append(String.format("%.0f", group.getExtract() == null ? BigDecimal.ZERO : group.getExtract())).append("\n");
        sb.append("\n");
        sb.append("<b>应下发: </b>").append(String.format("%.0f", batchInfo.getNeedGive())).append("\n");
        sb.append("<b>总下发: </b>").append(String.format("%.0f", batchInfo.getSumOutAmount())).append("\n");
        sb.append("<b>剩余: </b>").append(String.format("%.0f", batchInfo.getNeedGive().subtract(batchInfo.getSumOutAmount()))).append("\n");
        Date batchStartTime = group.getBatchStartTime();
        long time = System.currentTimeMillis() - batchStartTime.getTime();
        sb.append("\n");
        sb.append("已工作").append(time / 1000 / 60).append("分钟");
    }

    public BatchInfo getBatchInfo(OrderBatch orderBatch) {
        BatchInfo batchInfo = new BatchInfo();
        BeanUtils.copyProperties(orderBatch, batchInfo);
        BigDecimal sumInAmount = BigDecimal.ZERO;
        BigDecimal sumInU = BigDecimal.ZERO;
        BigDecimal sumOutAmount = BigDecimal.ZERO;
        BigDecimal needGive = BigDecimal.ZERO;
        List<Order> inOrders = getResultOrders("入款", orderBatch.getBatchId());
        for (Order order : inOrders) {
            if (Boolean.TRUE.equals(order.getIsDelete())) {
                continue;
            }
            if (Objects.isNull(order.getExtract())) {
                order.setExtract(BigDecimal.ZERO);
            }
            sumInAmount = sumInAmount.add(order.getAmount().subtract(order.getExtract()));
            if (order.getExchangeRate().compareTo(BigDecimal.ZERO) == 0) {
                order.setExchangeRate(BigDecimal.valueOf(1));
            }
            sumInU = sumInU.add(order.getAmount().subtract(order.getExtract()).divide(order.getExchangeRate(), 4, RoundingMode.HALF_UP));
            needGive = needGive.add(order.getAmount().subtract(order.getExtract()).subtract(order.getAmount().subtract(order.getExtract()).multiply(order.getRate())).divide(order.getExchangeRate(), 4, RoundingMode.HALF_UP));
        }
        List<Order> outOrders = getResultOrders("下发", orderBatch.getBatchId());
        for (Order order : outOrders) {
            if (Boolean.TRUE.equals(order.getIsDelete())) {
                continue;
            }
            if (order.getExchangeRate().compareTo(BigDecimal.ZERO) == 0) {
                order.setExchangeRate(BigDecimal.valueOf(1));
            }
            sumOutAmount = sumOutAmount.add(order.getAmount().divide(order.getExchangeRate(), 4, RoundingMode.HALF_UP));
        }
        batchInfo.setSumInAmount(sumInAmount);
        batchInfo.setSumInU(sumInU);
        batchInfo.setSumOutAmount(sumOutAmount);
        batchInfo.setNeedGive(needGive);
        batchInfo.setAllInOrders(inOrders);
        batchInfo.setAllOutOrders(outOrders);
        int start = inOrders.size() > 5 ? inOrders.size() - 5 : 0;
        batchInfo.setInOrders(inOrders.subList(start, inOrders.size()));
        start = outOrders.size() > 5 ? outOrders.size() - 5 : 0;
        batchInfo.setOutOrders(outOrders.subList(start, outOrders.size()));
        return batchInfo;
    }

    private LowerMessage getOptionLowerMessage(Update update) {
        Message replyToMessage = update.getMessage().getReplyToMessage();
        Long chatId = update.getMessage().getChatId();
        if (Objects.isNull(replyToMessage)) {
            return null;
        }
        Integer messageId = replyToMessage.getMessageId();
        List<LowerMessage> lowerMessages = lowerMessageService.lambdaQuery()
                .eq(LowerMessage::getMessageId, messageId)
                .eq(LowerMessage::getUpGroupId, chatId)
                .list();
        if (CollectionUtil.isEmpty(lowerMessages)) {
            return null;
        }
        return lowerMessages.get(0);
    }

    public void getBiResultString(StringBuilder sb, String orderType, List<Order> orders, List<Order> allOrders, BatchInfo batchInfo) {
        sb.append("<b>").append(orderType).append(": (").append(allOrders.size()).append("笔)</b>\n");
        for (Order od : orders) {
            String userName = " ";
            if (Boolean.TRUE.equals(batchInfo.getShowOderUser())) {
                userName = " " + od.getMemo() + " ";
            }
            if (Objects.isNull(od.getExtract())) {
                od.setExtract(BigDecimal.ZERO);
            }
            String extract = "";
            if (od.getExtract() != null && BigDecimal.ZERO.compareTo(od.getExtract()) != 0) {
                extract = "-" + String.format("%.0f", od.getExtract());
            }
            String clearText = Boolean.TRUE.equals(od.getIsDelete()) ? "（清理不入账）" : "";
            if ("下发".equals(orderType)) {
                sb.append(od.getId()).append(userName).append(DateUtil.format(od.getCreateTime(), "HH:mm:ss ")).append("<b>").append(String.format("%.0f", od.getAmount())).append(clearText).append("</b>\n");
            } else {
                sb.append(od.getId()).append(userName).append(DateUtil.format(od.getCreateTime(), "HH:mm:ss ")).append("<b>").append(String.format("%.0f", od.getAmount())).append(extract).append(" = ").append(String.format("%.0f", od.getAmount().subtract(od.getExtract()))).append(clearText).append("</b>\n");
            }
        }
    }

    private List<Order> getResultOrders(String orderType, String batchId) {
        return orderService.lambdaQuery()
                .eq(Order::getBatchId, batchId)
                .eq(Order::getType, orderType)
                .list();
    }

    @Override
    public String getCmdName() {
        return "+下发";
    }

    @Override
    public String getDescribe() {
        return "+                                 入款记账，如：+100U\n下发                           出账记账，如：下发100U\n";
    }
}
